/*
  Copyright (C) 2006 by Lukas Loehrer

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA

  Author: Massimiliano Mirra, <bard [at] hyperstruct [dot] net>
*/

// {{{ MetaService class

var BaseService = module.require("class", "services/base_service");

function MetaService(name, manager) {
	BaseService.call(this, name);
	this._manager = manager;
}

function listServices() {
	var serviceList = [];
	for (var name in this._manager._services) {
		if (this._manager._services.hasOwnProperty(name)) {
			serviceList.push(name);
		}
	}
	return serviceList;
}

MetaService.prototype = new BaseService("Services");
MetaService.prototype.listServices = listServices;

// }}}
// {{{ Service manager class

const logger = module.require("package", "lib/filelogger").logger;

function ServiceManager() {
	this._services = {};
	this.registerService(new MetaService("Services", this));
}

function registerService(service) {
	name = service._serviceName;
	if (name in this._services) {
		throw new Error("Service " + name + " already registered.");
	}
	this.reregisterService(name, service);
}

function reregisterService(name, service) {
	this._services[name] = service;
}

function invokeService(serviceName, methodName, args) {
	if (!(serviceName in this._services)) {
		throw new NoSuchService(serviceName);
	}
	var service = this._services[serviceName];
	if (!(methodName in service && service[methodName] instanceof Function)) {
		throw new NoSuchMethod(serviceName, methodName);
	}
	var method = service[methodName];
	try {
		return method.apply(service, args);
	} catch (e) {
		// TODO: Maybe we need some error handling here too
		throw e;
	}
}

function disconnectServices() {
	for (var s in this._services) {
		try {
			this._services[s]._disconnectService();
		} catch (e) {
			logger.error("service_manager.disconnect: Problem while shutting down service " + s + " " + e, e);
		}
	}
	this._services = {};
}

ServiceManager.prototype = {
	registerService: registerService,
	reregisterService: reregisterService,
	invokeService: invokeService,
	disconnectServices: disconnectServices
};

// }}}

// Special class to signal "return on event"
function ReturnLaterOnEvent(target, name, callback, useCapture, timeout) {
	this.eventTarget = target;
	this.eventName = name;
	this.callback = callback;
	this.useCapture = useCapture;
	this.timeout = timeout;
}
ReturnLaterOnEvent.prototype = new Object();


// {{{ Exceptions

function NoSuchService(serviceName) {
	Error.call(this);
	this._name = serviceName;
}
NoSuchService.prototype = new Error();

function InvalidArgument() {
	Error.call(this);
}
InvalidArgument.prototype = new Error();

function NoSuchMethod(serviceName, methodName) {
	Error.call(this);
	this._serviceName = serviceName;
	this._methodName =methodName;
}
NoSuchMethod.prototype = new Error();


// }}}



// {{{ Emacs local variables

// local variables:
// folded-file: t
// end:

// }}}
